/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/pgl.h>
#include <pgl/core/PGLPrinter.h>
#include <pgl/core/PGLRegion.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPGLPrinter::CPGLPrinter(CPGLRegion* pRegion)
:  m_pRegion(pRegion), m_rMargins(1,1,1,1), m_pPrinterDC(NULL), m_pPrintInfo(NULL)
{
}

CPGLPrinter::~CPGLPrinter()
{

}


void CPGLPrinter::PreparePage()
{
	// This function returns the area in device units to be used to
	// prints a page with a true boarder of "margin".
	//
	// You could use individual margins for each edge and apply below as needed.
	//
	ASSERT(m_pPrinterDC);

	// Set Map Mode - We do not want device units due to lack of consistency.
	// If you do not use TWIPS you will have to change the scaling factor below.
	m_pPrinterDC->SetMapMode(MM_TWIPS);

	// Variable needed to store printer info.
	CSize PrintOffset,Physical,Printable;

	// This gets the Physical size of the page in Device Units
	Physical.cx = m_pPrinterDC->GetDeviceCaps(PHYSICALWIDTH);
	Physical.cy = m_pPrinterDC->GetDeviceCaps(PHYSICALHEIGHT);
	// convert to logical
	m_pPrinterDC->DPtoLP(&Physical);

	// This gets the offset of the printable area from the
	// top corner of the page in Device Units
	PrintOffset.cx = m_pPrinterDC->GetDeviceCaps(PHYSICALOFFSETX);
	PrintOffset.cy = m_pPrinterDC->GetDeviceCaps(PHYSICALOFFSETY);
	// convert to logical
	m_pPrinterDC->DPtoLP(&PrintOffset);

	// Set Page scale to TWIPS, Which is 1440 per inch, Zero/Zero is the upper left corner
	// Get Printable Page Size (This is in MM!) so convert to twips.
	Printable.cx =  (int)((float)m_pPrinterDC->GetDeviceCaps(HORZSIZE)*56.69);
	Printable.cy = (int)((float)m_pPrinterDC->GetDeviceCaps(VERTSIZE)*56.69);

	// Positive X -> RIGHT
	// Positive Y -> UP
	// Ref Zero is upper left corner
	int inch = 1440; // Scaling Factor Inches to TWIPS
	int Dx1, Dx2, Dy1, Dy2; // Distance printable area is from edge of paper
	Dx1 = PrintOffset.cx;
	Dy1 = PrintOffset.cy;
	// calculate remaining borders
	Dy2 = Physical.cy-Printable.cy-Dy1;
	Dx2 = Physical.cx-Printable.cx-Dx1;
	//
	// Define the User Area's location
	ASSERT(m_pPrintInfo);
	m_pPrintInfo->m_rectDraw.left = (long)(m_rMargins.left*inch-Dx1);
	m_pPrintInfo->m_rectDraw.right = (long)(Printable.cx-m_rMargins.right*inch+Dx2);
	m_pPrintInfo->m_rectDraw.top = (int)-(m_rMargins.top*inch-Dy1); // My scale is inverted for y
	m_pPrintInfo->m_rectDraw.bottom = (int)-(Printable.cy-m_rMargins.bottom*inch+Dy2);
	// now put back to device units to return to the program.
	m_pPrinterDC->LPtoDP(&(m_pPrintInfo->m_rectDraw));

	//put MM_TEXT mode
	m_pPrinterDC->SetMapMode(MM_TEXT);

	// updating info structure
    m_pPrintInfo->m_nCurPage = m_pPrintInfo->GetMinPage();
}

double CPGLPrinter::ComputeDpiRatio()
{
	if(m_pPrintInfo->m_pPD)
	{
		DEVMODE* pDev=m_pPrintInfo->m_pPD->GetDevMode();
		double dpiRatio=300.0/pDev->dmPrintQuality;
		VERIFY(GlobalUnlock(pDev));

		return dpiRatio;
	}
	else
		return 1;
}

void CPGLPrinter::Print(CDC *pDC, CPrintInfo *pInfo)
{
	using namespace Gdiplus;
	using namespace gfxinterface;

	if (!m_pRegion)
		return;

	ASSERT(pDC);
	ASSERT(pInfo);
	ASSERT(m_pRegion);

	m_pPrinterDC = pDC;
	m_pPrintInfo = pInfo;

	PreparePage();

	Graphics graphics(pDC->m_hDC);
	CGDIpInterface gfx;

	// setting scaling
	// document if printing, other otherwize
	if (!pInfo->m_bPreview)
	{
		graphics.SetPageUnit(UnitDocument);		
		// getting dpiRatio
		double pgScale = ComputeDpiRatio();	
		// setting dpi ratio
		graphics.SetPageScale((float)pgScale);
		gfx.SetFontRatio(pgScale);
	}

	
	gfx.SetMainBoundingBox(m_pPrintInfo->m_rectDraw.left,
			m_pPrintInfo->m_rectDraw.top, m_pPrintInfo->m_rectDraw.right, m_pPrintInfo->m_rectDraw.bottom);

	// saves viewport info
	int vp[4];
	m_pRegion->GetViewport(vp);

	gfx.SetGraphics(&graphics);
	gfx.BeginPaint(m_pPrinterDC->m_hDC);

		// modify to page
		m_pRegion->SetViewport(m_pPrintInfo->m_rectDraw.left, m_pPrintInfo->m_rectDraw.top, 
				m_pPrintInfo->m_rectDraw.Width(),m_pPrintInfo->m_rectDraw.Height());
		// update view
		m_pRegion->RefreshView(gfx,true);
		// plot
		m_pRegion->PlotGfx(gfx);

	// shareware stuff
#ifdef _PGL_SHAREWARE
		gfx.SetColor(1,0,0,0.7);
		LOGFONT lf;
		lf.lfHeight=gfx.CreateFontSize(m_pPrinterDC->m_hDC, 15);
		gfx.SetFont(lf);
		gfx.DrawText(gfx.GetWorldLeft(),gfx.GetWorldBottom(),
			_T("Shareware Version of PGL"),TextAlignmentLeft,35);
#endif

		// restore viewport
		m_pRegion->SetViewport(vp[0], vp[1], vp[2], vp[3]);
		// update view
		m_pRegion->RefreshView(gfx,true);

	gfx.EndPaint();
}

